# -*- coding: utf-8 -*-
"""
Module Description: 接口服务维护
Date: 2017/12/22
Author:Bai Jin Ping
"""
import time

# from common.service_config import get_progress_list
# from pyshare.const import special_actionid
# from pyshare.const.enums.remote_service_switch import ServiceSwitch
# from pyshare.core.base_action import AuthAction
# from pyshare.distributed.role_lock import RoleLock
# from pyshare.utils.act_id_remark import global_act_remark
# from pyshare.framework.firefly_dc.global_errcode import GlobalErrCode
from framework.firefly_dc import runtime_logger as log
# from pyshare.const.lang.tips_info import TipsInfo
# from common import service_config
# from pyshare.framework.error_handle import GameException, CrossGameException, CrossAdminGameException
# from pyshare.framework import runtime_logger as log
# from pyshare.remote_services.session_service import SessionCode
from app.const.enums.server_info import SessionCode
from app.const.lang.tips_info import TipsInfo
from framework.firefly_dc.error_handle import GameException, CrossGameException, CrossAdminGameException
from framework.firefly_dc.global_errcode import GlobalErrCode
from utils.print_utils import echo
from utils.traceback_utils import print_exc


class ActionRemark(object):
    _remark_dict = {}

    def init_remark(self, act_id, remark):
        """
        初始化remark文本
        :param act_id: 接口id
        :param remark: 接口描述
        :return:
        """
        self._remark_dict[act_id] = remark

    def get_remark_by_act_id(self, act_id):
        """
        获取接口remark
        :param act_id: 接口id
        :return:
        """

        return self._remark_dict.get(act_id, "")


global_act_remark = ActionRemark()


class ActionService(object):
    """
    接口服务
    """

    # 维护接口号和接口处理类
    # {action_id: ActionClass}
    _targets = {}

    @classmethod
    def map_target_by_key(cls, key, target):
        """
        建立接口号和接口处理类的映射
        :param key:
        :param target:
        :return:
        """
        # 重复接口检测
        if cls._targets.has_key(key):
            exist_target = cls._targets.get(key)
            raise ValueError("ActionId [%d] Already exists,Conflict between the %s and %s"
                             % (key, exist_target.__name__, target.__name__))

        cls._targets[key] = target

        # 初始化接口remark
        global_act_remark.init_remark(key, str(cls._targets[key].__doc__))

    @classmethod
    def get_target(cls, target_key):
        """
        获得接口类
        :param target_key: action_id
        :return: 接口类
        """
        target = cls._targets.get(target_key)
        return target

    @classmethod
    def call_target(cls, request, response):
        """
        调用请求处理类
        :param request:
        :param response:
        """
        action_class = cls.get_target(request.action_id)
        action = action_class(request.args)

        # 进入上下文
        with request.ctx:
            try:
                if not action.before_action():
                    action.status_code = GlobalErrCode.FAILED
                    action.info = TipsInfo.GlobalKeys.authActionDataError

                elif not action.parse_arguments():
                    action.status_code = GlobalErrCode.FAILED
                    action.info = TipsInfo.GlobalKeys.paramError

                # 预处理报错，直接获取错误结果并返回
                if action.status_code == GlobalErrCode.FAILED:
                    response.set_attribute_dict(action.get_response())
                    return

                # 打印接口说明
                echo(request.action_id, action_class.__doc__.strip() if action_class.__doc__ else "")

                locker = None
                action_result = None
                # note: 登录/注册接口因为没有rid参数,因此需要在接口内自行加角色锁, 登录后拉取聊天消息也无需角色锁
                # if service_config.get_remote_service_switch(ServiceSwitch.ClientActionAutoRoleLock) \
                #         and (request.action_id not in special_actionid.ACTIONID_LIST_NOT_NEED_ROLE_LOCK) \
                #         and issubclass(action_class, AuthAction):
                #     try_lock_timeout = special_actionid.ACTIONID_LIST_NEED_LOCK_MORE_TIME.get(
                #         request.action_id, special_actionid.LOCK_TIME_DEFAULT
                #     )
                #     locker = RoleLock.lock(action.rid, try_lock_timeout=try_lock_timeout)
                #
                # if locker:
                #     with locker:
                #         # 经过try_lock_timeout时间尝试没有得到角色锁,说明上一个请求正在处理中,提示稍后重试
                #         if not locker.acquire_lock_success:
                #             raise GameException(TipsInfo.GlobalKeys.requestFailedPleaseTryAgain, stat=GlobalErrCode.PLEASE_TRY_AGAIN)
                #
                #         # 加角色锁调用接口逻辑
                #         action_result = action.take_action()
                # else:
                # 调用接口逻辑
                action_result = action.take_action()

                if not action_result:
                    if action.status_code == GlobalErrCode.SUCCESS:
                        raise GameException(TipsInfo.GlobalKeys.unknownMistake)

                action.end_time = time.time()

                # 构造响应对象
                response.set_attribute_dict(action.get_response())
                # 有返回头才更新
                if action.get_headers():
                    # 增加返回头
                    response.headers = action.get_headers()

                # 为了写入接口日志，在action response增加参数
                if response.response.get("SessionCode"):
                    action.add_response("SessionCode", response.response.get("SessionCode", SessionCode.success))
                if response.response.get("SessionResult"):
                    action.add_response("SessionResult", response.response.get("SessionResult", {}))

                # 后续处理,如记录日志等
                if not action.is_error():
                    action.after_action()
                else:
                    # TODO: 后续都要以GameException形式抛出
                    # 若不是返回正常的状态码，打印
                    error_str = u"action req(args={args}) error(code={code}):{msg}".format(code=action.status_code,
                                                                                           args=action.args,
                                                                                           msg=action.info)
                    log.warning(error_str)

            # 处理(游戏业务异常,跨服游戏异常状态,跨服后台异常状态)
            except (GameException, CrossGameException, CrossAdminGameException) as ge:
                response.set_info(info=ge.message, stat=ge.stat, force_clear=True)
                if ge.extra is not None:
                    response.set_attribute_dict(ge.extra)

                # 改为参数传入，和Traceback日志整合成一条，减少日志条目数，便于排查问题
                # log.warning(ge.message,
                #           # 这个extra对应logging.Logger._log()的extra参数
                #           extra={
                #               # 这个extra对应EventFormatter的extra
                #               'extra': {
                #                   'exception': ge.__class__.__name__,
                #                   'args': action.args,
                #                   'code': ge.stat,
                #               }
                #           }
                # )

                extra = {
                    # 这个extra对应EventFormatter的extra
                    'extra': {
                        'Tips': ge.message,
                        'stat': ge.stat,
                    }
                }

                print_exc(ge, request_args=action.args, log_level='warning', extra=extra)
            # 处理预料之外的处理异常
            except Exception as e:
                # 强制清理返回数据,设置错误信息
                response.set_info(info=TipsInfo.GlobalKeys.defaultErrorInfo, stat=GlobalErrCode.ERROR, force_clear=True)
                extra = {
                    # 这个extra对应EventFormatter的extra
                    'extra': {
                        'Tips': TipsInfo.GlobalKeys.defaultErrorInfo,
                        'stat': GlobalErrCode.ERROR,
                    }
                }
                # 打印异常时增加打印请求参数，方便排查
                print_exc(e, request_args=request.args, extra=extra)
